package com.qty.apkviewer.activities

import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageInfo
import android.os.Bundle
import android.os.Environment
import android.text.TextUtils
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import com.qty.apkviewer.BaseActivity
import com.qty.apkviewer.R
import com.qty.apkviewer.log.QLog
import com.qty.apkviewer.utils.Constants
import com.qty.apkviewer.utils.PermissionUtils
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.file.Files
import java.nio.file.StandardCopyOption

class ApkInfoActivity : BaseActivity(), View.OnClickListener {

    private lateinit var iconIv: ImageView
    private lateinit var nameTv: TextView
    private lateinit var versionTv: TextView
    private lateinit var packageNameTv: TextView
    private lateinit var mainClassNameTv: TextView
    private lateinit var copyApkBtn: Button
    private lateinit var startApkBtn: Button
    private lateinit var packageInfoTv: TextView
    private lateinit var applicationInfoTv: TextView
    private lateinit var activitiesInfoTv: TextView
    private lateinit var servicesInfoTv: TextView
    private lateinit var receiversInfoTv: TextView
    private lateinit var providersInfoTv: TextView

    private var name: String? = null
    private var packageName: String? = null
    private var mainClassName: String? = null
    private var packageInfo: PackageInfo? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_apk_info)

        supportActionBar?.setDisplayHomeAsUpEnabled(true)

        iconIv = findViewById(R.id.icon)
        nameTv = findViewById(R.id.name)
        versionTv = findViewById(R.id.version)
        packageNameTv = findViewById(R.id.package_name)
        mainClassNameTv = findViewById(R.id.main_class_name)
        copyApkBtn = findViewById(R.id.copy_apk)
        startApkBtn = findViewById(R.id.start_app)
        packageInfoTv = findViewById(R.id.package_info)
        applicationInfoTv = findViewById(R.id.application_info)
        activitiesInfoTv = findViewById(R.id.activities_info)
        servicesInfoTv = findViewById(R.id.services_info)
        receiversInfoTv = findViewById(R.id.receivers_info)
        providersInfoTv = findViewById(R.id.providers_info)

        copyApkBtn.setOnClickListener(this)
        startApkBtn.setOnClickListener(this)
        packageInfoTv.setOnClickListener(this)
        applicationInfoTv.setOnClickListener(this)
        activitiesInfoTv.setOnClickListener(this)
        servicesInfoTv.setOnClickListener(this)
        receiversInfoTv.setOnClickListener(this)
        providersInfoTv.setOnClickListener(this)

        intent.let {
            name = it.getStringExtra(Constants.EXTRA_APK_NAME)
            packageName = it.getStringExtra(Constants.EXTRA_APK_PACKAGE)
            mainClassName = it.getStringExtra(Constants.EXTRA_APK_MAIN_CLASSNAME)
        }

        if (packageName == null) {
            finish()
        } else {
            packageInfo = packageManager.getPackageInfo(packageName!!, 0)
            packageInfo?.let {
                val icon = it.applicationInfo.loadIcon(packageManager)
                iconIv.setImageDrawable(icon)
                nameTv.text = it.applicationInfo.loadLabel(packageManager)
                versionTv.text = it.versionName
                packageNameTv.text = it.packageName
                setTitle(nameTv.text)
            }
            if (!TextUtils.isEmpty(mainClassName)) {
                mainClassNameTv.text = mainClassName
                startApkBtn.isEnabled = true
            } else {
                mainClassNameTv.setText(R.string.not_found)
                startApkBtn.isEnabled = false
            }
        }
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return if (item.itemId == android.R.id.home) {
            finish()
            true
        } else {
            super.onOptionsItemSelected(item)
        }

    }

    override fun onClick(v: View?) {
        v?.apply {
            when (id) {
                R.id.copy_apk -> {
                    if (PermissionUtils.checkStoragePermission(this@ApkInfoActivity)) {
                        copyApk()
                    } else {
                        PermissionUtils.requestStoragePermisson(this@ApkInfoActivity) {result ->
                            if (!result) {
                                Toast.makeText(this@ApkInfoActivity,
                                    context.getString(R.string.permission_denied), Toast.LENGTH_SHORT).show()
                            }
                        }
                    }
                }
                R.id.start_app -> {
                    val intent = Intent()
                    intent.component = ComponentName(packageName!!, mainClassName!!)
                    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                    startActivity(intent)
                }
                R.id.package_info -> {

                }
                R.id.application_info -> {

                }
                R.id.activities_info -> {

                }
                R.id.services_info -> {

                }
                R.id.receivers_info -> {

                }
                R.id.providers_info -> {

                }
            }
        }
    }

    private fun copyApk() {
        if (packageInfo != null) {
            packageInfo?.let {
                val nativeLibraryDir = it.applicationInfo.nativeLibraryDir
                val sourceDir = it.applicationInfo.sourceDir
                val splitSourceDirs = it.applicationInfo.splitSourceDirs
                val targetDirPath = getCopyDir()
                copyDir(nativeLibraryDir, targetDirPath)
                copyFile(sourceDir, targetDirPath)
                splitSourceDirs?.let {dirs ->
                    for (dir in dirs) {
                        copyDir(dir, targetDirPath)
                    }
                }
                QLog.d(this, "copyApk=>nativeLibraryDir: $nativeLibraryDir")
                QLog.d(this, "copyApk=>sourceDir: $sourceDir")
                QLog.d(this, "copyApk=>splitSourceDir: ${splitSourceDirs.contentToString()}")
                Toast.makeText(this, getString(R.string.copy_to, targetDirPath), Toast.LENGTH_LONG).show()
            }
        } else {
            Toast.makeText(this, getString(R.string.copy_fail), Toast.LENGTH_SHORT).show()
        }
    }

    private fun getCopyDir(): String {
        val documentDir = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
        val dir = File(documentDir, packageInfo!!.applicationInfo.loadLabel(packageManager).toString())
        if (dir.exists() && dir.isDirectory) {
            dir.delete()
        }
        dir.mkdirs()
        return dir.absolutePath
    }

    private fun copyDir(dirPath: String, targetDirPath: String) {
        QLog.d(this, "copyDir=>dirPath: $dirPath, targetDirPath: $targetDirPath")
        val file = File(dirPath)
        val files = file.listFiles()
        if (files != null) {
            val newFile = File(targetDirPath, file.name)
            if (!newFile.exists() || !newFile.isDirectory) {
                newFile.mkdirs()
            }
            for (f in files) {
                if (f.isDirectory) {
                    copyDir(f.absolutePath, newFile.absolutePath)
                } else {
                    copyFile(f.absolutePath, newFile.absolutePath)
                }
            }
        }
    }

    private fun copyFile(filePath: String, targetPath: String) {
        QLog.d(this, "copyFile=>filePath: $filePath, targetPath: $targetPath")
        val file = File(filePath)
        val newFile = File(targetPath, file.name)
        if (newFile.exists() && newFile.isFile) {
            newFile.delete()
        }
        newFile.createNewFile()
        FileInputStream(file).use { fis ->
            FileOutputStream(newFile).use { fos ->
                val bis = fis.buffered()
                val bos = fos.buffered()
                bis.copyTo(bos)
                bos.flush()
            }
        }
    }
}